﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using MediaPortal.Configuration;
using MediaPortal.Dialogs;
using MediaPortal.GUI.Library;
using MediaPortal.GUI.Music;
using MediaPortal.Music.Database;
using MediaPortal.Profile;
using MediaPortal.TagReader;
using MediaPortal.Util;
using Action = MediaPortal.GUI.Library.Action;

namespace MusicInfoHandler
{

  [PluginIcons("GUIRadioLastFM.BallonRadio.gif", "GUIRadioLastFM.BallonRadioDisabled.gif")]
  public class MusicInfoHandlerGUI : GUIWindow, ISetupForm
  {

    #region variables

    private enum SkinControlIDs
    {
      LST_ITEMS = 50
    }

    private enum ViewLevel
    {
      Top,
      Artist,
      AlbumArtist,
      Album
    }

    private ViewLevel _viewLevel;
    private static bool _strippedPrefixes;
    private static string _artistPrefixes;
    private const string StrArtistSQL = "select distinct rtrim(strArtist) from artist where lower(strArtist) not in (select lower(strArtist) from artistinfo) order by 1";
    private const string StrAlbumArtistSQL = "select distinct rtrim(strAlbumArtist) from albumartist where lower(rtrim(strAlbumArtist)) not in (select lower(strArtist) from artistinfo) and lower(strAlbumArtist) not like 'various artists'order by 1";
    private const string StrAlbumSQL = "select distinct lower(strAlbum), rtrim(ltrim(lower(strAlbumArtist), '| '), ' |') from tracks " +
                               "EXCEPT " +
                               "select lower(strAlbum), lower(strArtist) from albumInfo order by 2,1";
    private const string AlbumRegExpPattern = @"<td class=""title primary_link"".*?<a href=""(?<albumURL>.*?)"" class=""title.*?"" data-tooltip="".*?"">(?<albumName>.*?)</a>";
    private static readonly Regex AlbumURLRegEx = new Regex(AlbumRegExpPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);

    [SkinControl((int)SkinControlIDs.LST_ITEMS)] protected GUIFacadeControl MissingItems = null;


    #endregion

    #region ISetupForm methods

    /// <summary>
    ///   Determines whether this plugin can be enabled.
    /// </summary>
    /// <returns>
    ///   <c>true</c> if this plugin can be enabled; otherwise, <c>false</c>.
    /// </returns>
    public bool CanEnable()
    {
      return true;
    }

    /// <summary>
    ///   Determines whether this plugin has setup.
    /// </summary>
    /// <returns>
    ///   <c>true</c> if this plugin has setup; otherwise, <c>false</c>.
    /// </returns>
    public bool HasSetup()
    {
      return false;
    }

    /// <summary>
    ///   Gets the plugin name.
    /// </summary>
    /// <returns>The plugin name.</returns>
    public string PluginName()
    {
      return "MusicInfoHandler GUI";
    }

    /// <summary>
    ///   Defaults enabled.
    /// </summary>
    /// <returns>true if this plugin is enabled by default, otherwise false.</returns>
    public bool DefaultEnabled()
    {
      return true;
    }

    /// <summary>
    ///   Gets the window id.
    /// </summary>
    /// <returns>The window id.</returns>
    public int GetWindowId()
    {
      return GetID;
    }

    /// <summary>
    ///   Gets the plugin author.
    /// </summary>
    /// <returns>The plugin author.</returns>
    public string Author()
    {
      return "Jameson_uk";
    }

    /// <summary>
    ///   Gets the description of the plugin.
    /// </summary>
    /// <returns>The plugin description.</returns>
    public string Description()
    {
      return
        "GUI For Album / Artist scraping";
    }

    /// <summary>
    ///   Shows the plugin configuration.
    /// </summary>
    public void ShowPlugin()
    {
      return;
    }

    /// <summary>
    ///   Gets the home screen details for the plugin.
    /// </summary>
    /// <param name = "strButtonText">The button text.</param>
    /// <param name = "strButtonImage">The button image.</param>
    /// <param name = "strButtonImageFocus">The button image focus.</param>
    /// <param name = "strPictureImage">The picture image.</param>
    /// <returns>true if the plugin can be seen, otherwise false.</returns>
    public bool GetHome(out string strButtonText, out string strButtonImage, out string strButtonImageFocus,
                        out string strPictureImage)
    {
      strButtonText = "MusicInfoHandler";
      strButtonImage = string.Empty;
      strButtonImageFocus = string.Empty;
      strPictureImage = @"hover_my music.png";
      return true;
    }

    public override int GetID
    {
      get
      {
        return 1599;
      }

      set
      {
      }
    }

    #endregion ISetupForm methods

    #region GUI Methods

    public override bool Init()
    {
      return Load(GUIGraphicsContext.GetThemedSkinFile(@"\MusicInfoHandler.xml"));
    }

    public override string GetModuleName()
    {
      return PluginName();
    }

    protected override void OnPageLoad()
    {
      _strippedPrefixes = MPSettings.Instance.GetValueAsBool("musicfiles", "stripartistprefixes", false);
      _artistPrefixes = MPSettings.Instance.GetValueAsString("musicfiles", "artistprefixes", "The, Les, Die");

      LoadTopLevel();
      MissingItems.EnableSMSsearch = true;
      base.OnPageLoad();
    }

    protected override void OnClicked(int controlId, GUIControl control, MediaPortal.GUI.Library.Action.ActionType actionType)
    {
      base.OnClicked(controlId, control, actionType);

      if (control == MissingItems)
      {
        if (actionType == MediaPortal.GUI.Library.Action.ActionType.ACTION_SELECT_ITEM)
        {
          var x = MissingItems.SelectedListItem;

          if (x.IsFolder)
          {
            LoadTopLevel();
            return;
          }

          switch (_viewLevel)
          {
            case ViewLevel.Top:
              LoadList(x);
              break;
            case ViewLevel.Artist:
            case ViewLevel.AlbumArtist:
              ShowArtistInfo(x.Label);
              break;
            case ViewLevel.Album:
              var tag = (MusicTag)x.MusicTag;
              ShowAlbumInfo(GetID, tag.AlbumArtist, tag.Album, tag);
              break;
          }
        }
      }

    }

    public override void OnAction(Action action)
    {
      if (action.wID == Action.ActionType.ACTION_PREVIOUS_MENU)
      {
        if (_viewLevel != ViewLevel.Top)
        {
          LoadTopLevel();
          return;
        }
      }
      base.OnAction(action);
    }

    private void LoadTopLevel()
    {
      MissingItems.CurrentLayout = MediaPortal.GUI.Library.GUIFacadeControl.Layout.List;
      MissingItems.Clear();
      MissingItems.Add(new GUIListItem { Label = "Missing Artists" });
      MissingItems.Add(new GUIListItem { Label = "Missing Album Artists" });
      MissingItems.Add(new GUIListItem { Label = "Missing Albums" });
      _viewLevel = ViewLevel.Top;
      GUIPropertyManager.SetProperty("#itemcount", string.Empty);
      GUIPropertyManager.SetProperty("#currentmodule", string.Empty);
    }

    private void LoadList(GUIListItem item)
    {
      switch (item.Label)
      {
        case "Missing Artists":
          _viewLevel = ViewLevel.Artist;
          break;
        case "Missing Album Artists":
          _viewLevel = ViewLevel.AlbumArtist;
          break;
        case "Missing Albums":
          _viewLevel = ViewLevel.Album;
          break;
      }

      switch (_viewLevel)
      {
        case ViewLevel.Artist:
          LoadMissingArtists();
          break;
        case ViewLevel.AlbumArtist:
          LoadMissingAlbumArtists();
          break;
        case ViewLevel.Album:
          LoadMissingAlbums();
          break;
      }
    }

    private void LoadMissingArtists()
    {
      var i = 0;
      _viewLevel = ViewLevel.Artist;
      MissingItems.Clear();
      MissingItems.Add(new GUIListItem { Label = "..", IsFolder = true });
      var artistResults = MusicDatabase.DirectExecute(StrArtistSQL);
      foreach (var strArtist in artistResults.Rows.Select(row => row.fields[0]).Where(strArtist => !string.IsNullOrEmpty(strArtist.Trim())).Where(strArtist => strArtist.ToLower() != "unknown" && strArtist.ToLower() != "various" && strArtist.ToLower() != "various artists"))
      {
        var x = new GUIListItem { Label = strArtist };
        x.OnRetrieveArt += OnRetrieveCoverArt;
        MissingItems.Add(x);
        i++;
      }
        
      GUIPropertyManager.SetProperty("#itemcount", i.ToString(CultureInfo.InvariantCulture));
      GUIPropertyManager.SetProperty("Missing Artists", string.Empty);
    }

    private void LoadMissingAlbumArtists()
    {
      var i = 0;
      _viewLevel = ViewLevel.AlbumArtist;
      MissingItems.Clear();
      MissingItems.Add(new GUIListItem { Label = "..", IsFolder = true });
      var artistResults = MusicDatabase.DirectExecute(StrAlbumArtistSQL);
      foreach (var strArtist in artistResults.Rows.Select(row => row.fields[0]).Where(strArtist => !string.IsNullOrEmpty(strArtist.Trim())).Where(strArtist => strArtist.ToLower() != "unknown" && strArtist.ToLower() != "various" && strArtist.ToLower() != "various artists"))
      {
        var x = new GUIListItem {Label = strArtist };
        x.OnRetrieveArt += OnRetrieveCoverArt;
        MissingItems.Add(x);
        i++;
      }
      GUIPropertyManager.SetProperty("#itemcount", i.ToString(CultureInfo.InvariantCulture));
      GUIPropertyManager.SetProperty("#currentmodule", "Missing Album Artists");
    }

    private void LoadMissingAlbums()
    {
      var i = 0;
      _viewLevel = ViewLevel.Album;
      MissingItems.Clear();
      MissingItems.Add(new GUIListItem { Label = "..", IsFolder = true });
      var albumResults = MusicDatabase.DirectExecute(StrAlbumSQL);
      foreach (var row in albumResults.Rows)
      {
        var strAlbum = row.fields[0].Trim();
        var strAlbumArtist = row.fields[1].Trim();

        if (strAlbumArtist == "Various Artists") continue;

        var tag = new MusicTag { AlbumArtist = strAlbumArtist, Album = strAlbum, Artist = strAlbumArtist };

        var x = new GUIListItem
          {
            Label = string.Format("{0} - {1}", strAlbumArtist, strAlbum),
            MusicTag = tag,
          };
        x.OnRetrieveArt += OnRetrieveCoverArt;
        MissingItems.Add(x);
        i++;
      }
      GUIPropertyManager.SetProperty("#itemcount", i.ToString(CultureInfo.InvariantCulture));
      GUIPropertyManager.SetProperty("#currentmodule", "Missing Albums");
    }

    private void ShowArtistInfo(string artistName)
    {
      Log.Debug("Looking up Artist: {0}", artistName);

      var dlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);
      var pDlgOK = (GUIDialogOK)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_OK);

      var errorEncountered = true;
      var artist = new ArtistInfo();
      var artistInfo = new MusicArtistInfo();
      if (MusicDatabase.Instance.GetArtistInfo(artistName, ref artist))
      { // we already have artist info in database so just use that
        artistInfo.Set(artist);
        errorEncountered = false;
      }
      else
      { // lookup artist details

        if (null != pDlgOK && !Win32API.IsConnectedToInternet())
        {
          pDlgOK.SetHeading(703);
          pDlgOK.SetLine(1, 703);
          pDlgOK.SetLine(2, string.Empty);
          pDlgOK.DoModal(GetID);
          return;
        }

        // show dialog box indicating we're searching the artist
        if (dlgProgress != null)
        {
          dlgProgress.Reset();
          dlgProgress.SetHeading(320);
          dlgProgress.SetLine(1, artistName);
          dlgProgress.SetLine(2, string.Empty);
          dlgProgress.SetPercentage(0);
          dlgProgress.StartModal(GetID);
          dlgProgress.Progress();
          dlgProgress.ShowProgressBar(true);
        }

        var scraper = new AllmusicSiteScraper();
        List<AllMusicArtistMatch> artists;

        var strCleanArtistName = artistName;
        if (_strippedPrefixes)
        {
          strCleanArtistName = UndoArtistPrefix(artistName);
        }

        if (scraper.GetArtists(strCleanArtistName, out artists))
        {
          var selectedMatch = new AllMusicArtistMatch();
          if (artists.Count == 1)
          { // only have single match so no need to ask user
            Log.Debug("Single Artist Match Found");
            selectedMatch = artists[0];
            errorEncountered = false;
          }
          else
          {
            // need to get user to choose which one to use
            Log.Debug("Muliple Artist Match Found ({0}) prompting user", artists.Count);
            var pDlg = (GUIDialogSelect2)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_SELECT2);
            if (null != pDlg)
            {
              pDlg.Reset();
              pDlg.SetHeading(GUILocalizeStrings.Get(1303));
              foreach (var i in artists.Select(artistMatch => new GUIListItem
              {
                Label = artistMatch.Artist + " - " + artistMatch.Genre,
                Label2 = artistMatch.YearsActive,
                Path = artistMatch.ArtistUrl,
                IconImage = artistMatch.ImageUrl
              }))
              {
                pDlg.Add(i);
              }
              pDlg.DoModal(GetID);

              // and wait till user selects one
              var iSelectedMatch = pDlg.SelectedLabel;
              if (iSelectedMatch < 0)
              {
                return;
              }
              selectedMatch = artists[iSelectedMatch];
            }

            if (null != dlgProgress)
            {
              dlgProgress.Reset();
              dlgProgress.SetHeading(320);
              dlgProgress.SetLine(1, artistName);
              dlgProgress.SetLine(2, string.Empty);
              dlgProgress.SetPercentage(40);
              dlgProgress.StartModal(GetID);
              dlgProgress.ShowProgressBar(true);
              dlgProgress.Progress();
            }
          }
          string strHtml;
          if (scraper.GetArtistHtml(selectedMatch, out strHtml))
          {
            if (null != dlgProgress)
            {
              dlgProgress.SetPercentage(60);
              dlgProgress.Progress();
            }
            if (artistInfo.Parse(strHtml))
            {
              if (null != dlgProgress)
              {
                dlgProgress.SetPercentage(80);
                dlgProgress.Progress();
              }
              // because we are cleansing artist name during search it might no longer reflect the original
              // one tagged against tracks.   Reset this
              artistInfo.Artist = artistName;
              MusicDatabase.Instance.AddArtistInfo(artistInfo.Get());

              //TODO: at this point we should loop over albums for this artist if there were multiple matches
              errorEncountered = false;
            }
          }
        }
      }

      if (null != dlgProgress)
      {
        dlgProgress.SetPercentage(100);
        dlgProgress.Progress();
        dlgProgress.Close();
        dlgProgress = null;
      }

      if (!errorEncountered)
      {
        var pDlgArtistInfo = (GUIMusicArtistInfo)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_ARTIST_INFO);
        if (null != pDlgArtistInfo)
        {
          pDlgArtistInfo.Artist = artistInfo;
          pDlgArtistInfo.DoModal(GetID);

          if (pDlgArtistInfo.NeedsRefresh)
          {
            MusicDatabase.Instance.DeleteArtistInfo(artistInfo.Artist);
            ShowArtistInfo(artistName);
          }
        }
        if (_viewLevel == ViewLevel.Artist)
        {
          LoadMissingArtists();
        }
        else
        {
          LoadMissingAlbumArtists();
        }
      }
      else
      {
        Log.Debug("Unable to get artist details");

        if (null != pDlgOK)
        {
          pDlgOK.SetHeading(702);
          pDlgOK.SetLine(1, 702);
          pDlgOK.SetLine(2, string.Empty);
          pDlgOK.DoModal(GetID);
        }
      }
    }

    private void ShowAlbumInfo(int parentWindowID, string artistName, string albumName, MusicTag tag)
    {
      Log.Debug("Searching for album: {0} - {1}", albumName, artistName);

      var dlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);
      var pDlgOK = (GUIDialogOK)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_OK);

      var errorEncountered = true;
      var album = new AlbumInfo();
      var albumInfo = new MusicAlbumInfo();
      var selectedMatch = new AllMusicArtistMatch();
      if (MusicDatabase.Instance.GetAlbumInfo(albumName, artistName, ref album))
      {
        // we already have album info in database so just use that
        albumInfo.Set(album);
        errorEncountered = false;
      }
      else
      {
        // lookup details.  start with artist

        if (null != pDlgOK && !Win32API.IsConnectedToInternet())
        {
          pDlgOK.SetHeading(703);
          pDlgOK.SetLine(1, 703);
          pDlgOK.SetLine(2, string.Empty);
         
          pDlgOK.DoModal(GetID);
          return;
        }

        // show dialog box indicating we're searching the album
        if (dlgProgress != null)
        {
          dlgProgress.Reset();
          dlgProgress.SetHeading(326);
          dlgProgress.SetLine(1, albumName);
          dlgProgress.SetLine(2, artistName);
          dlgProgress.SetPercentage(0);
          dlgProgress.StartModal(GetID);
          dlgProgress.Progress();
          dlgProgress.ShowProgressBar(true);
        }

        var scraper = new AllmusicSiteScraper();
        List<AllMusicArtistMatch> artists;

        var strCleanArtistName = artistName;
        if (_strippedPrefixes)
        {
          strCleanArtistName = UndoArtistPrefix(artistName);
        }

        if (scraper.GetArtists(strCleanArtistName, out artists))
        {
          if (null != dlgProgress)
          {
            dlgProgress.SetPercentage(20);
            dlgProgress.Progress();
          }
          if (artists.Count == 1)
          {
            selectedMatch = artists[0];
          }
          else
          {
            // need to get user to choose which one to use
            Log.Debug("Muliple Artist Match Found ({0}) prompting user", artists.Count);
            var pDlg = (GUIDialogSelect2)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_SELECT2);
            if (null != pDlg)
            {
              pDlg.Reset();
              pDlg.SetHeading(GUILocalizeStrings.Get(1303));

              foreach (var i in artists.Select(artistMatch => new GUIListItem
              {
                Label = artistMatch.Artist + " - " + artistMatch.Genre,
                Label2 = artistMatch.YearsActive,
                Path = artistMatch.ArtistUrl,
                IconImage = artistMatch.ImageUrl
              }))
              {
                pDlg.Add(i);
              }
              pDlg.DoModal(GetID);

              // and wait till user selects one
              var iSelectedMatch = pDlg.SelectedLabel;
              if (iSelectedMatch < 0)
              {
                return;
              }
              selectedMatch = artists[iSelectedMatch];
            }

            if (null != dlgProgress)
            {
              dlgProgress.Reset();
              dlgProgress.SetHeading(326);
              dlgProgress.SetLine(1, albumName);
              dlgProgress.SetLine(2, artistName);
              dlgProgress.SetPercentage(40);
              dlgProgress.StartModal(GetID);
              dlgProgress.ShowProgressBar(true);
              dlgProgress.Progress();
            }
          }

          string strAlbumHtml;
          if (scraper.GetAlbumHtml(albumName, selectedMatch.ArtistUrl, out strAlbumHtml))
          {
            if (null != dlgProgress)
            {
              dlgProgress.SetPercentage(60);
              dlgProgress.Progress();
            }
            if (albumInfo.Parse(strAlbumHtml))
            {
              if (null != dlgProgress)
              {
                dlgProgress.SetPercentage(80);
                dlgProgress.Progress();
              }
              // because we are cleansing artist and album name during search it might no longer reflect the original
              // one tagged against tracks.   Reset this
              albumInfo.Artist = artistName;
              albumInfo.Title = albumName;
              MusicDatabase.Instance.AddAlbumInfo(albumInfo.Get());
              errorEncountered = false;
            }

          }
        }
      }

      if (errorEncountered)
      {
        if (null != dlgProgress)
        {
          dlgProgress.SetPercentage(90);
          dlgProgress.Progress();
        }

        var albums = GetAlbumList(selectedMatch.ArtistUrl, albumName);
        if (albums.Count > 0)
        {
          var pDlg = (GUIDialogSelect2) GUIWindowManager.GetWindow((int) GUIWindow.Window.WINDOW_DIALOG_SELECT2);
          if (null != pDlg)
          {
            pDlg.Reset();
            pDlg.SetHeading(GUILocalizeStrings.Get(181));
            foreach (var i in albums.Select(albumMatch => new GUIListItem
              {
                Label = albumMatch.AlbumName,
                Path = albumMatch.AlbumName
              }))
            {
              pDlg.Add(i);
            } //TODO add a back option?
            pDlg.DoModal(GetID);

            // and wait till user selects one
            var iSelectedMatch = pDlg.SelectedLabel;
            if (iSelectedMatch >= 0)
            {
              string strHtml;
              if (GetHtml(albums[iSelectedMatch].AlbumUrl, out strHtml))
              {
                if (albumInfo.Parse(strHtml))
                {
                  // because we are cleansing artist and album name during search it might no longer reflect the original
                  // one tagged against tracks.   Reset this
                  albumInfo.Artist = artistName;
                  albumInfo.Title = albumName;
                  MusicDatabase.Instance.AddAlbumInfo(albumInfo.Get());
                  errorEncountered = false;
                }

              }
            }
          }
        }
      }

      if (null != dlgProgress)
      {
        dlgProgress.SetPercentage(100);
        dlgProgress.Progress();
        dlgProgress.Close();
        dlgProgress = null;
      }

      if (!errorEncountered)
      {
        var pDlgAlbumInfo = (GUIMusicInfo)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_MUSIC_INFO);
        if (null != pDlgAlbumInfo)
        {
          pDlgAlbumInfo.Album = albumInfo;

          pDlgAlbumInfo.DoModal(parentWindowID);
          if (pDlgAlbumInfo.NeedsRefresh)
          {
            MusicDatabase.Instance.DeleteAlbumInfo(albumName, artistName);
            ShowAlbumInfo(parentWindowID, artistName, albumName, tag);
            return;
          }
        }
        LoadMissingAlbums();
      }
      else
      {
        Log.Debug("No Album Found");

        if (null != pDlgOK)
        {
          pDlgOK.SetHeading(187);
          pDlgOK.SetLine(1, 187);
          pDlgOK.SetLine(2, string.Empty);
          pDlgOK.DoModal(GetID);
        }
      }
    }

    protected void OnRetrieveCoverArt(GUIListItem item)
    {
      string strThumb = string.Empty;

      switch (_viewLevel)
      {
        case ViewLevel.Artist:
        case ViewLevel.AlbumArtist:
          strThumb = MediaPortal.Util.Utils.GetCoverArt(Thumbs.MusicArtists, item.Label);
          if (MediaPortal.Util.Utils.FileExistsInCache(strThumb))
          {
            item.IconImage = strThumb;
            item.IconImageBig = strThumb;
            item.ThumbnailImage = strThumb;
          }
          break;
        case ViewLevel.Album:
          bool thumbFound = false;
          var tag = item.MusicTag as MusicTag;
          strThumb = MediaPortal.Util.Utils.GetAlbumThumbName(tag.Artist, tag.Album);
          if (MediaPortal.Util.Utils.FileExistsInCache(strThumb))
          {
            item.IconImage = strThumb;
            item.IconImageBig = strThumb;
            item.ThumbnailImage = strThumb;
            thumbFound = true;
          }

          if (item.IsFolder && !thumbFound)
          {
            strThumb = MediaPortal.Util.Utils.GetLocalFolderThumb(item.Path);
            if (MediaPortal.Util.Utils.FileExistsInCache(strThumb))
            {
              item.IconImage = strThumb;
              item.IconImageBig = strThumb;
              item.ThumbnailImage = strThumb;
            }
          }
          break;
      }

      // let us test if there is a larger cover art image
      if (string.IsNullOrEmpty(strThumb)) return;
      string strLarge = MediaPortal.Util.Utils.ConvertToLargeCoverArt(strThumb);
      if (MediaPortal.Util.Utils.FileExistsInCache(strLarge))
      {
        item.ThumbnailImage = strLarge;
      }
    }

    #endregion

    /// <summary>
    /// taken from audioscrobbler plugin code to reverse where prefix has been swapped 
    /// eg. The Beatles => Beatles, The or Die Toten Hosen => Toten Hosen ,Die
    /// and will change back to the artist name
    /// </summary>
    /// <param name="aStrippedArtist">Value stored in database with prefix at the end</param>
    /// <returns>What should be actual string in tag</returns>
    private static string UndoArtistPrefix(string aStrippedArtist)
    {
      try
      {
        string[] allPrefixes = null;
        allPrefixes = _artistPrefixes.Split(',');
        if (allPrefixes.Length > 0)
        {
          for (int i = 0; i < allPrefixes.Length; i++)
          {
            string cpyPrefix = allPrefixes[i];
            if (!aStrippedArtist.ToLowerInvariant().EndsWith(cpyPrefix.ToLowerInvariant())) continue;
            // strip the separating "," as well
            int prefixPos = aStrippedArtist.IndexOf(',');
            if (prefixPos <= 0) continue;
            aStrippedArtist = aStrippedArtist.Remove(prefixPos);
            cpyPrefix = cpyPrefix.Trim(new char[] { ' ', ',' });
            aStrippedArtist = cpyPrefix + " " + aStrippedArtist;
            // abort here since artists should only have one prefix stripped
            return aStrippedArtist;
          }
        }
      }
      catch (Exception ex)
      {
        Log.Error("AudioscrobblerBase: An error occured undoing prefix strip for artist: {0} - {1}", aStrippedArtist,
                  ex.Message);
      }

      return aStrippedArtist;
    }


    private static List<AlbumMatch> GetAlbumList(string strArtistUrl, string strAlbumName)
    {
      var fullUrl = strArtistUrl + "/overview/main#discography";

      var albums = new List<AlbumMatch>();
      string strHtml;
      if (!GetHtml(fullUrl, out strHtml))
      {
        return albums;
      }

      for (var m = AlbumURLRegEx.Match(strHtml); m.Success; m = m.NextMatch())
      {
        var album = new AlbumMatch
          {
            AlbumName = System.Web.HttpUtility.HtmlDecode(m.Groups["albumName"].ToString()),
            AlbumUrl = m.Groups["albumURL"].ToString(),
            MatchScore = Levenshtein.Match(strAlbumName, m.Groups["albumName"].ToString())
          };

        albums.Add(album);
      }

      fullUrl = strArtistUrl + "/overview/compilations#discography";
      if (!GetHtml(fullUrl, out strHtml))
      {
        return albums;
      }

      for (var m = AlbumURLRegEx.Match(strHtml); m.Success; m = m.NextMatch())
      {
        var album = new AlbumMatch
        {

          AlbumName = System.Web.HttpUtility.HtmlDecode(m.Groups["albumName"].ToString()),
          AlbumUrl = m.Groups["albumURL"].ToString(),
          MatchScore = Levenshtein.Match(strAlbumName, m.Groups["albumName"].ToString())
        };

        albums.Add(album);
      }

      var sortedAlbums = albums.OrderBy(x => x.MatchScore).ToList();

      return sortedAlbums;
    }

    #region HTTP

    private static bool GetHtml(string strURL, out string strHtml)
    {
      strHtml = string.Empty;
      try
      {
        var x = (HttpWebRequest)WebRequest.Create(strURL);

        x.ProtocolVersion = HttpVersion.Version10;
        x.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0";
        x.ContentType = "text/html";
        x.Timeout = 30000;
        x.AllowAutoRedirect = false;

        using (var y = (HttpWebResponse)x.GetResponse())
        {
          using (var z = y.GetResponseStream())
          {
            if (z == null)
            {
              x.Abort();
              y.Close();
              return false;
            }
            using (var sr = new StreamReader(z, Encoding.UTF8))
            {
              strHtml = sr.ReadToEnd();
            }

            z.Close();
            x.Abort();
            y.Close();
          }
        }
      }
      catch (Exception ex)
      {
        Log.Error("AMG Scraper: Error retrieving html for: {0}", strURL);
        Log.Error(ex);
        return false;
      }

      return true;
    }

    #endregion

    private class AlbumMatch
    {
      public string AlbumName { get; set; }
      public string AlbumUrl { get; set; }
      public int MatchScore { get; set; }
    }

  }
}
